home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************/
- /* Calls Program to analyse program calls */
- /* Reference: The C Programming Tutor p223 - A. DeSouza 5/3/85 */
- /************************************************************************/
- /* include files */
- /************************************************************************/
- #include <c:stdio.h>
- #include <a:calls.h>
-
-
- /************************************************************************/
- /* external functions */
- /************************************************************************/
- extern NamePtrType FindNameEntry();
- extern NamePtrType LookFor();
- extern char *malloc();
-
- /************************************************************************/
- /* global variables */
- /************************************************************************/
- NamePtrType ActiveList [MAXDEPTH] ;
- /* used by output to avoid infinite recursion.
- */
- int BracketCount = 0 ;
- /* keeps track of the nesting of brackets. a function found when
- * BracketCount is 0 must be its DEFINING occurence, since function
- * invocations must always appear within some block of code.
- */
- FILE *FilePtr ; /*input file pointer */
- char *HashTable[HTSIZE] ;
- int LineCount = 0 ;
- int MaxActiveIndex = 0 ;
- /* Indexes ActiveList from 0 to MAXDEPTH.
- */
- NamePtrType NameListHead ;
- FILE *OutFile ;
- int TabsPerPage = (PAPERWIDTH-MAXSYMLENGTH)/TABSIZE ;
- /* default number of pages per page
- */
- BOOL Terse = TRUE ;
-
- /***********************************************************************/
- /* main */
- /***********************************************************************/
-
- VOID main(argc,argv)
- int argc ;
- char *argv [] ;
- { /* main */
- int ActListIndex ;
- int ArgIndex = 1 ;
- char Identifier[MAXSYMLENGTH] ;
- NamePtrType CallerPtr ;
- char FileName[80] ;
- int FunctionUse ;
- int HTIndex ;
- NamePtrType NamePtr ;
-
- NameListHead = GenericNULL(NameType) ;
-
- /* initialize the hash table.
- */
- for (HTIndex = 0 ; (HTIndex < HTSIZE ) ; HTIndex++)
- HashTable[HTIndex] = GenericNULL(char) ;
-
- /* the following are keywords that look like function
- calls in C
- */
- InsertWord("for") ;
- InsertWord("if") ;
- InsertWord("return") ;
- InsertWord("sizeof") ;
- InsertWord("switch") ;
- InsertWord("while") ;
-
- /* Initialize the active list
- */
- for (ActListIndex = 0 ; (ActListIndex < MAXDEPTH) ; )
- ActiveList[ActListIndex++] = GenericNULL(NameType) ;
-
- /* there must be at least one command-line option
- */
- if (argc < 2) {
- printf("USAGE: %s\n",USAGE) ;
- exit(0) ;
- }
-
- /* determine the input file and open it
- */
- if (ArgIndex < argc ) {
- /* extract the filename from the command line */
-
- strcpy(FileName,argv[ArgIndex++]) ;
- if (!(FilePtr = fopen(FileName,"r")))
- Error("Specified file cannot be opened",TRUE);
- }
- /* parse the input stream and build the appropriate tables.
- */
- CallerPtr = GenericNULL(NameType) ;
- while ((FunctionUse =
- FindNextFunction(Identifier,CallerPtr)) != EOF )
- if (FunctionUse == DEFINING )
- CallerPtr = FindNameEntry(Identifier) ;
- else
- NewOccurrence(Identifier,CallerPtr) ;
- /* if there are any command line arguments, they are the names
- of the functions from which to begin the call charts
- */
- if (ArgIndex < argc) {
- do {
- if (NamePtr = LookFor(argv[ArgIndex])) {
- Output(NamePtr,0) ;
- printf("\n\n") ;
- }
- else
- Error(
- "starting function from command line not found",FALSE) ;
- }
- while ((++ArgIndex) < argc) ;
- }
- else {
- /* print beginning with 'main', if there is one */
- if (NamePtr = LookFor("main")) {
- Output(NamePtr,0) ;
- printf("\n\n") ;
- NamePtr->CallCount = 1 ;
- /* don't print "main" again later. */
- }
-
- /* now print all functions not called by anyone else */
- for (NamePtr = NameListHead ; NamePtr ;
- NamePtr = NamePtr->NextNamePtr )
- if (NamePtr-> CallCount == 0) {
- Output(NamePtr,0) ;
- printf("\n\n") ;
- }
- /* Finally, print any mutually recursive functions. */
- for (NamePtr = NameListHead ; NamePtr ;
- NamePtr = NamePtr->NextNamePtr)
- if (NamePtr->FirstLineNumber == 0) {
- Output(NamePtr,0) ;
- printf("\n\n") ;
- }
- }
- } /* main */
-
-
- VOID Output(NamePtr, CurTab)
- NamePtrType NamePtr;
- int CurTab;
- /* A recursive routine that prints one tab for each level of
- * nesting, then the name of the function called, followed by the
- * next function called at the same level. In doing this, it
- * invokes itself to Output the names of the functions called by
- * the current function. It maintains an active list of functions
- * currently being Output by the different levels of recursion,
- * and if it finds itself asked to Output one which is already
- * active, it terminates, marking that call with an asterisk.
- */
- { /* Output */
- InstPtrType InstPtr;
- int LoopCount;
- int NumOfTabs = CurTab;
- BOOL PageOverflow;
- int TabCount;
-
- LineCount++;
- printf("\n%4d",LineCount);
- if (!(MakeActive(NamePtr)))
- printf("*"); /* Calls nested too deep */
- else {
- for (TabCount = 0; (NumOfTabs > TabsPerPage); TabCount++)
- NumOfTabs -= TabsPerPage;
- for (LoopCount = 0; (LoopCount < TabCount); LoopCount++)
- printf("<");
- printf(" ");
- for (LoopCount = 0; (LoopCount < NumOfTabs); LoopCount++)
- printf("\t");
-
- if (IsActive(NamePtr)) /* recursive call */
- printf("%s [recursive]", NamePtr->FunctionName);
- else {
- InstPtr = NamePtr->FirstCallee;
- if (InstPtr != GenericNULL(InstanceType)) {
- printf("%s", NamePtr->FunctionName);
- if (!Terse || (NamePtr->FirstLineNumber == 0)) {
- CurTab++;
- if (NamePtr->FirstLineNumber == 0)
- NamePtr->FirstLineNumber = LineCount;
- if ((CurTab > TabsPerPage) &&
- (CurTab % TabsPerPage == 1) &&
- (InstPtr->NextCallee
- != GenericNULL(InstanceType))) {
- printf(
- "\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _");
- printf(" _ _ _ _ _ _ _ _ _ _");
- PageOverflow = TRUE;
- }
- else PageOverflow = FALSE;
-
- for ( ; (InstPtr != GenericNULL(InstanceType));
- InstPtr = InstPtr->NextCallee)
- Output(InstPtr->NameDefinition, CurTab);
-
- if (PageOverflow) {
- printf(
- "\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _");
- printf(" _ _ _ _ _ _ _ _ _ _");
- PageOverflow = FALSE;
- }
- }
- else if (InstPtr != GenericNULL(InstanceType))
- printf("... [see line %d]", NamePtr->FirstLineNumber);
- }
- else printf("%s", NamePtr->FunctionName);
- /* library, external, or macro call */
- }
- BackUp();
- if (NamePtr->FirstLineNumber == 0)
- NamePtr->FirstLineNumber = LineCount;
- }
- } /* Output */
-
-
- BOOL MakeActive(CurNameEntry)
- NamePtrType CurNameEntry;
- /* Puts a pointer to the argument NameEntry into the ActiveList.
- * FALSE is returned if the function fails because the function
- * nesting is too deep; otherwise TRUE is returned.
- */
- { /* MakeActive */
- if (MaxActiveIndex < MAXDEPTH) {
- ActiveList[MaxActiveIndex++] = CurNameEntry;
- return (TRUE);
- }
- else return (FALSE);
- } /* MakeActive */
-
-
- BOOL IsActive(CurNameEntry)
- NamePtrType CurNameEntry;
- /* Checks if its argument is already on the actove list. */
- { /* IsActive */
- int ActListIndex;
-
- for (ActListIndex =0; (ActListIndex < MaxActiveIndex-1);
- ActListIndex++)
- if (CurNameEntry == ActiveList[ActListIndex])
- return (TRUE);
- return (FALSE);
- } /* IsActive */
-
-
- VOID BackUp ()
- /* Pops an item from the active list.
- */
- { /* BackUp */
- assert(MaxActiveIndex > 0);
- ActiveList[MaxActiveIndex--] = NULL;
- } /* BackUp */
-
-
- int FindNextFunction(Identifier, CurFunction)
- char *Identifier ;
- NamePtrType CurFunction ;
- /* Sets its argument to the name of the next function found
- * in the input stream. It returns as its value DEFINING if this
- * is the DEFINING occurrence of the function, DEFINED if it is
- * simply an invocation of the function, and EOF if the input stream
- * is exhausted.
- */
- { /*FindNextFunction */
- int CurChar ;
-
- while (TRUE) {
- CurChar = getc(FilePtr) ;
- if (IsStartingLetter(CurChar)) {
- ungetc(CurChar,FilePtr) ;
- Scan(Identifier) ;
- }
- else {
- switch(CurChar) {
- case '\t':
- case BLANK:
- /* Skip over white space */
- break ;
- case EOL:
- /* Skip over preprocessor lines */
- if ((CurChar = getc(FilePtr)) == '#' )
- while ((CurChar = getc(FilePtr)) != EOL)
- if (CurChar == '\\')
- getc(FilePtr) ; /*Continuation */
- ungetc(CurChar,FilePtr) ;
- break ;
-
- case '\'':
- /* This doesn't work if the literal contains a quoted
- apostrophe (\'). */
- Identifier[0] = EOS ;
- /* Skip over character literals */
- while ((CurChar = getc(FilePtr)) != '\'')
- if (CurChar == '\\')
- getc(FilePtr) ; /* Continuation */
- break ;
-
- case '\"':
- /* This doesn't work if literal contains a quoted
- quotation mark (\") */
- /* skip over string literals */
- while ((CurChar = getc(FilePtr)) != '\"')
- if (CurChar == '\\')
- getc(FilePtr) ; /* Continuation */
- break ;
-
- case '\\':
- Identifier[0] = EOS ;
- getc(FilePtr) ;
- break ;
-
- case '{':
- BracketCount++ ;
- Identifier[0] = EOS ;
- getc(FilePtr) ;
- break ;
-
- case '}':
- BracketCount-- ;
- if (BracketCount < 0 )
- Error("Brackets are not properly nested",FALSE) ;
- Identifier[0] = EOS ;
- break ;
-
- case '(':
- if (Identifier[0] == EOS)
- break ; /* No function name was found. */
-
- /* Ignore any works occurring in the hash table */
- if ( !FindWord(Identifier)) {
- /* Not within the body of a function */
- if (BracketCount == 0)
- return(DEFINING) ;
-
- else if (!Seen(Identifier,CurFunction))
- return(DEFINED) ;
- /* Ignore nultiple occurances within a function */
- }
- Identifier[0] = EOS ;
- break ;
-
- case EOF:
- return(EOF) ;
-
- case '/':
- if ((CurChar = getc(FilePtr)) == '*') {
- /* Skip over comments */
- while (TRUE) {
- while ( getc(FilePtr) != '*') ;
- if ((CurChar = getc(FilePtr)) == '/')
- break;
- ungetc(CurChar,FilePtr) ;
- }
- }
- else ungetc(CurChar,FilePtr) ;
- break ;
-
- /* All over characters must delimit Identifiers */
- default:
- Identifier[0] = EOS ;
- break ;
-
- } /* switch */
- } /* else */
- } /* while */
- } /* FindNextFunction */
-
-
- VOID Scan(Token)
- char *Token ;
- /* Scans the input stream until a token is found that might
- be the name of a function. It returns the atom found. */
- { /* Scan */
- int CurChar ;
- int StringIndex ;
-
- for (StringIndex = 0 ;
- CurChar = getc(FilePtr), IsStartingLetter(CurChar) ; ) {
- Token[StringIndex++] = CurChar ;
- if (StringIndex >= MAXSYMLENGTH) {
- StringIndex = MAXSYMLENGTH - 1 ;
- break ;
- }
- }
- assert(StringIndex < MAXSYMLENGTH) ;
- Token[StringIndex] = EOS ;
- ungetc(CurChar,FilePtr) ;
- } /* Scan */
-
-
-
- BOOL FindWord(Word)
- char *Word ;
- /* Looks up an identifier in the hash table and returns TRUE or
- FALSE to indicate the presence or absence of the identifier */
- { /* FindWord */
- int Hash();
- int HTIndex = Hash(Word) ;
- if ((HTIndex == HASHTABLEFULLFLAG) ||
- (HashTable[HTIndex] == GenericNULL(char)))
- return(FALSE) ;
- return(TRUE) ;
- } /* FindWord */
-
-
-
-
- BOOL Seen(CheckID, CurFunction)
- char *CheckID ;
- NamePtrType CurFunction ;
- /* Determines if the argument string CheckID has already been
- seen as an argument function */
- { /* Seen */
- InstPtrType InstPtr ;
-
- assert(CurFunction != GenericNULL(NameType)) ;
-
- for (InstPtr = CurFunction ->FirstCallee ;
- (InstPtr != GenericNULL(InstanceType)) ;
- InstPtr = InstPtr->NextCallee)
- if (StrEq(CheckID,(InstPtr->NameDefinition)->FunctionName))
- return(TRUE) ;
-
- return (FALSE) ;
-
- } /*Seen */
-
-
-
- NamePtrType FindNameEntry(Name)
- char *Name ;
- /* Returns a pointer to the argument name on the list of
- Nameentries. if the name is not there, a new Nameentry
- is created */
-
- { /* FindNameEntry */
- NamePtrType LastNamePtr = NULL ;
- NamePtrType NamePtr ;
- NamePtrType NewNamePtr ;
- NamePtrType AllocNameEntry() ;
- int StrTest ;
-
- /* Search for the name in the current list of known, defined
- functions. since the names are inserted in sorted order,
- stop when we have passed the new name in the list. */
-
- for(NamePtr = NameListHead ;
- NamePtr != NULL &&
- (StrTest = strcmp(Name,NamePtr->FunctionName)) >= 0 ;
- LastNamePtr = NamePtr,
- NamePtr = NamePtr->NextNamePtr)
- if ( StrTest == 0 )
- return(NamePtr) ;
-
- /* Name was not found, so add it */
-
- NewNamePtr = AllocNameEntry();
- strcpy(NewNamePtr->FunctionName,Name) ;
-
- /* Link the new name entry into the appropriate place in the chain */
- NewNamePtr->NextNamePtr = NamePtr ;
- if (!LastNamePtr)
- NameListHead = NewNamePtr ;
- else
- LastNamePtr->NextNamePtr = NewNamePtr ;
- return (NewNamePtr) ;
-
- } /* FindNameEntry */
-
-
-
-
- NamePtrType AllocNameEntry()
- /* Allocates storage for a NameEntry */
- { /* AllocNameEntry */
- NamePtrType NamePtr ;
-
- if (!(NamePtr = GenericMalloc(NameType)))
- Error("Ran out of memory",TRUE) ;
-
- /* Initialize the new entry */
- NamePtr->FunctionName[0] = EOS ;
- NamePtr->CallCount = 0 ;
- NamePtr->FirstLineNumber = 0 ;
- NamePtr->FirstCallee = GenericNULL(InstanceType) ;
- NamePtr->NextNamePtr = GenericNULL(NameType) ;
-
- return (NamePtr) ;
-
- } /* AllocNameEntry */
-
-
-
-
- VOID NewOccurrence(Name,CallerPtr)
- char *Name ;
- NamePtrType CallerPtr;
- /* Creates an instanceentry for a function use */
- { /* NewOccurrence */
- InstPtrType InstPtr ;
- NamePtrType NamePtr ;
- InstPtrType NewInstPtr ;
- InstPtrType AllocInstanceEntry();
-
- assert(CallerPtr != GenericNULL(NameType)) ;
-
- /* Create the new instance and link it with a NameType describing it */
- InstPtr = CallerPtr->FirstCallee ;
- NamePtr = FindNameEntry(Name) ;
- NewInstPtr = AllocInstanceEntry() ;
- NewInstPtr->NameDefinition = NamePtr ;
-
- if (InstPtr != GenericNULL(InstanceType)) {
- /* Run down the callee chain until a NULL link is found */
- for ( ; (InstPtr->NextCallee != GenericNULL(InstanceType)) ;
- InstPtr = InstPtr->NextCallee)
- ; /* no body */
-
- /* Now add the new instance to the callee chain */
- InstPtr->NextCallee = NewInstPtr ;
-
- }
- else
- CallerPtr->FirstCallee = NewInstPtr ;
-
- /* Increment the callee's call count */
-
- (NamePtr->CallCount)++ ;
-
- } /* NewOccurrance */
-
-
-
-
-
- InstPtrType AllocInstanceEntry()
- /* Allocates storage for InstanceEntry */
- { /* AllocInstanceEntry */
- InstPtrType InstPtr ;
- if (!(InstPtr = GenericMalloc(InstanceType)))
- Error("Ran out of memory",TRUE) ;
-
- InstPtr->NameDefinition = GenericNULL(NameType) ;
- InstPtr->NextCallee = GenericNULL(InstanceType) ;
-
- return(InstPtr) ;
-
- } /* AllocInstanceEntry */
-
-
-
-
-
-
-
-
-
- NamePtrType LookFor(Name)
- char *Name ;
- /* Looks for its argument name on the list of NameEntries
- if found, it returns a pointer to the entry; otherwise
- , it returns a NULL. */
-
- { /* LookFor */
- NamePtrType NamePtr ;
-
- for (NamePtr = NameListHead ;
- (NamePtr != GenericNULL(NameType)) ;
- NamePtr = NamePtr->NextNamePtr)
-
- if (StrEq(Name,NamePtr->FunctionName))
- return(NamePtr) ;
-
- return(GenericNULL(NameType)) ;
-
- } /* LookFor */
-
-
- char *Copy(OldString)
- char *OldString ;
- /* Copy makes a copy of OldString and returns the address of the copy */
- { /* Copy */
- char *NewString ;
- char *ReturnPtr ;
-
- /* allocate a string able to hold the length
- of the string plus one for the terminator */
- ReturnPtr = NewString = malloc(strlen(OldString) + 1) ;
-
- /* Copy the string and return a pointer to it */
- while (*NewString++ = *OldString++) ;
- return(ReturnPtr) ;
-
- } /* Copy */
-
-
-
-
- VOID Error(Message,AbortFlag)
- /* Reports any errors detected */
- char *Message ;
- BOOL AbortFlag ;
- { /* Error */
- fprintf(stderr,"\n*** calls: %s. ***\n",Message) ;
- if (AbortFlag)
- exit(0) ;
-
- } /* Error */
-
-
-
- int Hash(Word)
- char *Word ;
- /* Generates a unique hash table index for the argument
- identifier. the value of HASHTABLEFULLFLAG is returned
- if the hash table overflows */
-
- { /* Hash */
- int HTIndex ;
- int InitHTIndex ;
- int ProbeCounter = 0 ;
-
- HTIndex = InitHTIndex = TransformId(Word) ;
- assert(strlen(Word) > 0) ;
-
- if (HashTable[HTIndex] == GenericNULL(char))
- ; /* no-op - we've got it */
-
- else /* Have we found the correct index */
- if (StrEq(Word,HashTable[HTIndex]))
- ; /* DONE: a direct hit */
-
- else /* Collision -- generate indexes */
- for ( ; (ProbeCounter < (HTSIZE/2)) ; ProbeCounter++) {
- HTIndex = GenerateNewIndex(InitHTIndex, ProbeCounter) ;
- if ((HashTable[HTIndex] == GenericNULL(char)) ||
- StrEq(Word,HashTable[HTIndex]))
- break ; /* we've got it */
- }
- if (ProbeCounter >= (HTSIZE/2))
- return(HASHTABLEFULLFLAG) ;
- return(HTIndex) ;
-
- } /* Hash */
-
-
-
-
- BOOL InsertWord(Word)
- char *Word ;
- /* Inserts an identifier into the Hash table and returns TRUE.
- if the Hash table overflows, FALSE is returned */
-
- { /* InsertWord */
- int HTIndex ;
-
- if ((HTIndex = Hash(Word)) == HASHTABLEFULLFLAG)
- return(FALSE) ;
-
- /* add Word to the Hash table if it is not already present */
- if (HashTable[HTIndex] == GenericNULL(char))
- HashTable[HTIndex] = Copy(Word) ;
-
- return(TRUE) ;
-
- } /* InsertWord */
-
-
-
-
-
-
-
- BOOL IsStartingLetter(Ch)
- char Ch ;
- /* IsStartingLetter returns TRUE if Ch is a valid character to
- begin a C token */
-
- { /* IsStartingLetter */
- return((isalpha(Ch) || Ch == '_') ? TRUE : FALSE) ;
-
- } /* IsStartingLetter */
-
-
-
-
-
-
- int TransformId(Word)
- char Word[] ;
- /* Converts an identifier into an integer within the index
- range of HashTable. a ploynomial is generated and reduced
- modulo HTSIZE to produce this number */
-
- { /* TransformId */
- int Term = 0 ;
- int Wordindex ;
-
- for (Wordindex = strlen(Word)-1 ; (Wordindex >= 0) ; Wordindex--)
- Term = (257*Term) + Word[Wordindex] ;
-
- Term = abs(Term) ;
- return(Term % HTSIZE ) ;
-
- } /* TransformId */
-
-
-
-